package proceso;

import disco.*;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.SynchronousQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import tiempo.Temporizador;


public class DispatchPeticiones implements Runnable {

    long tiempoPeticionPrevia;
    private Map treeCFQRequest; //árbol de peticiones
    SynchronousQueue<CFQRequest> sq;
    

    public DispatchPeticiones(LinkedList<Proceso> listaProcesos,
            SynchronousQueue<CFQRequest> sq) {
        this.treeCFQRequest = Collections.synchronizedMap(new TreeMap());
        this.sq = sq;
        construirArbolCFQRequest(listaProcesos);     
        new Thread(this, "DispatchPeticiones").start();
       
    }
            
     /**
     * Ordena todas las peticiones por tiempo
     */
    public void construirArbolCFQRequest(LinkedList<Proceso> listaProcesos) {
        Iterator itr = listaProcesos.iterator();
        while (itr.hasNext()) {
            Proceso proceso = (Proceso) itr.next();
            Iterator itrPeticion = proceso.getListaPeticiones().iterator();
            while (itrPeticion.hasNext()) {
                Peticion peticion = (Peticion) itrPeticion.next();
                CFQRequest request = new CFQRequest(proceso.getPid(),
                        peticion.getTipo(), proceso.getPrioridad(),
                        peticion.getBloque(), peticion.getTiempoPeticion());
                this.treeCFQRequest.put(peticion.getTiempoPeticion(), request);
            }
        }
    }
    
    public void run() {
        LinkedList<CFQRequest> lista = new LinkedList<CFQRequest>(treeCFQRequest.values());
        int n = 0;
        while (true) {
            if (lista.isEmpty()) {
                break;
            }
            CFQRequest cfqRequest = lista.removeFirst();
            try {
                //Se duerme el tiempo de diferencia entre llegadas.
                Thread.sleep(cfqRequest.getTiempoPeticion() - tiempoPeticionPrevia);
                
                sq.put(cfqRequest);
                n++;
//                System.out.println("dp " + n);
            } catch (InterruptedException ex) {
                Logger.getLogger(DispatchPeticiones.class.getName()).log(Level.SEVERE, null, ex);
            }
            
            tiempoPeticionPrevia = cfqRequest.getTiempoPeticion();
            final String toAppend = cfqRequest.toString();
            
            //Interfaz
            try{
                SwingUtilities.invokeAndWait(new Runnable() {
                    public void run() {
                        disco.Main.actualizarPeticionesProcesosGui(toAppend);
                    }
                });
            } catch (InvocationTargetException ex) {
//                Logger.getLogger(DispatchPeticiones.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InterruptedException e) {
//                Logger.getLogger(DispatchPeticiones.class.getName()).log(Level.SEVERE, null, e);
            }
                Temporizador.sleep();
        }       
    }
}
